package com.test.redis.chapter1.vote;

import java.time.Instant;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import com.test.redis.pool.RedisConnectionPoolUtil;

import redis.clients.jedis.Jedis;

public class ArticleVoteSystem {

    public static final String ARTICLE_ID = "article:id";
    public static final String ARTICLE_KEY_PREFIX = "article:%d";
    public static final String ARTICLE_PUBLISH_TIME_ZSET = "article:publish:time";
    public static final String ARTICLE_SCORE_ZSET_PREFIX = "article:score";
    public static final String ARTICLE_INFO_HASH_PREFIX = "article:info:%s";
    public static final String ARTICLE_VOTE_USER_SET_PREFIX = "article:vote:user:%s";
    public static final String ARTICLE_GROUP_PREFIX = "article:group:%d";

    //文章允许投票的最大时间
    public static final double ARTICLE_VOTE_MAX_TIME = 7*24*3600*1.0;

    //投一张票对应的分值
    public static final double SCORE_PER_VOTE = 432*1.0;

    public void initSystem() {
        Jedis jedis = RedisConnectionPoolUtil.getJedis();
        jedis.set(ARTICLE_ID, "1");
    }

    /**
     * 文章发布
     */
    public long publishArticle(ArticleInfo articleInfo) {
        try (Jedis jedis = RedisConnectionPoolUtil.getJedis()) {
            // 生成文章ID
            long articleId = jedis.incr(ARTICLE_ID);
            articleInfo.setId(articleId);

            // 存储文章发布时间
            long publishTimestamp = Instant.now().getEpochSecond();
            String articleKey = String.format(ARTICLE_KEY_PREFIX, articleId);
            jedis.zadd(ARTICLE_PUBLISH_TIME_ZSET, publishTimestamp, articleKey);
            jedis.zadd(ARTICLE_SCORE_ZSET_PREFIX, publishTimestamp, articleKey);

            // 存储文章信息
            Map<String, String> articleInfoMap = new HashMap<>();
            articleInfoMap.put(ArticleInfoAttr.ID.getValue(), Long.toString(articleId));
            articleInfoMap.put(ArticleInfoAttr.TITLE.getValue(), articleInfo.getTitle());
            articleInfoMap.put(ArticleInfoAttr.URL.getValue(), articleInfo.getUrl());
            articleInfoMap.put(ArticleInfoAttr.AUTHOR.getValue(), articleInfo.getAuthor());
            articleInfoMap.put(ArticleInfoAttr.PUBLISH_DATE.getValue(), Long.toString(publishTimestamp));
            articleInfoMap.put(ArticleInfoAttr.VOTE_COUNT.getValue(), "0");
            jedis.hset(String.format(ARTICLE_INFO_HASH_PREFIX, articleId), articleInfoMap);

            return articleId;
        } catch (Exception e) {
            // 异常处理
            throw new RuntimeException("文章发布失败", e);
        }
    }

    /**
     * 文章投票
     */
    public boolean voteArticle(long articleId,String userId){
        //判断文章是否允许投票
        try(Jedis jedis = RedisConnectionPoolUtil.getJedis()){
            double articlePublishTimestamp = jedis.zscore(ARTICLE_PUBLISH_TIME_ZSET,String.format(ARTICLE_KEY_PREFIX, articleId));
            //判断有没有超出投票时间
            if(articlePublishTimestamp - Instant.now().getEpochSecond() > ARTICLE_VOTE_MAX_TIME){
                return false;
            }
            //将用户添加到文章的投票集合中
            long addResult = jedis.sadd(String.format(ARTICLE_VOTE_USER_SET_PREFIX, articleId),userId);
            //添加成功
            if(addResult == 1){
                jedis.zincrby(ARTICLE_SCORE_ZSET_PREFIX,SCORE_PER_VOTE,String.format(ARTICLE_KEY_PREFIX, articleId));
                jedis.hincrBy(String.format(ARTICLE_INFO_HASH_PREFIX,articleId),ArticleInfoAttr.VOTE_COUNT.getValue(),1);
                return true;
            }
            return false;
        }
    }

    /**
     * 按指定顺序获取文章列表
     * @param page 要获取的文章页数，从1开始
     * @param pageSize 每页文章数量
     * @param orderBy 文章排序方式，score-按文章得分降序，time-按时间降序
     * @return
     */
    public List<ArticleInfo> getArticleList(int page,int pageSize,String orderBy){
        int start = (page-1)*pageSize;
        int end = start + pageSize - 1;
        String zsetKey = orderBy == "score" ? ARTICLE_SCORE_ZSET_PREFIX : ARTICLE_PUBLISH_TIME_ZSET;
        try(Jedis jedis = RedisConnectionPoolUtil.getJedis()){
            List<String> articleKeys = jedis.zrevrange(zsetKey,start,end);
            //取出每篇文章的详细信息
            List<ArticleInfo> articleInfos = articleKeys.stream().map(key->{
                String id = key.split(":")[1];
                ArticleInfo articleInfo = new ArticleInfo();
                Map<String,String> articleInfoMap = jedis.hgetAll(String.format(ARTICLE_INFO_HASH_PREFIX,id));
                articleInfo.setId(Long.parseLong(id));
                articleInfo.setAuthor(articleInfoMap.get(ArticleInfoAttr.AUTHOR.getValue()));
                articleInfo.setTitle(articleInfoMap.get(ArticleInfoAttr.TITLE.getValue()));
                articleInfo.setUrl(articleInfoMap.get(ArticleInfoAttr.URL.getValue()));
                articleInfo.setPublishDate(new Date(1000*Long.parseLong(articleInfoMap.get(ArticleInfoAttr.PUBLISH_DATE.getValue()))));
                articleInfo.setVoteCount(Long.parseLong(articleInfoMap.get(ArticleInfoAttr.VOTE_COUNT.getValue())));
                return articleInfo;
            }).collect(Collectors.toList());
            return articleInfos;
        }
    }

    /**
     * 将文章添加到分组中或者移除分组
     */
    public void addRemoveGroups(long articleId, List<Long> toAddGroups, List<Long> toRemoveGroups) {
        try (Jedis jedis = RedisConnectionPoolUtil.getJedis()) {
            String articleKey = String.format(ARTICLE_KEY_PREFIX, articleId);

            // 处理添加组
            if (toAddGroups != null && !toAddGroups.isEmpty()) {
                toAddGroups.forEach(groupId -> {
                    String groupKey = String.format(ARTICLE_GROUP_PREFIX, groupId);
                    jedis.sadd(groupKey, articleKey);
                });
            }

            // 处理移除组
            if (toRemoveGroups != null && !toRemoveGroups.isEmpty()) {
                toRemoveGroups.forEach(groupId -> {
                    String groupKey = String.format(ARTICLE_GROUP_PREFIX, groupId);
                    jedis.srem(groupKey, articleKey);
                });
            }
        }
    }

    public void close(){
        //清空存储的所有文章信息
        try(Jedis jedis = RedisConnectionPoolUtil.getJedis()){
            //先取出最新的文章ID
            long currentMaxId = Long.parseLong(jedis.get(ARTICLE_ID));
            //删除 文章发布时间zset,文章得分zset
            jedis.del(ARTICLE_PUBLISH_TIME_ZSET,ARTICLE_SCORE_ZSET_PREFIX);
            //从1遍历到currentMaxId，删除所有文章信息
            for(long i=1;i<=currentMaxId;i++){
                //删除文章信息hash
                jedis.del(String.format(ARTICLE_INFO_HASH_PREFIX,i));
                //删除文章投票用户集合
                jedis.del(String.format(ARTICLE_VOTE_USER_SET_PREFIX,i));
            }
            //清除所有group
            Set<String> groupKeys = jedis.keys(ARTICLE_GROUP_PREFIX+"*");
            groupKeys.stream().map(groupKey->{
                return jedis.del(groupKey);
            });
        }
    }

}
